package com.czy.jdbc.util;

import com.czy.jdbc.annotation.table.PK;
import com.czy.jdbc.annotation.table.Table;
import com.czy.util.model.MyMap;
import com.czy.util.model.StringMap;
import com.czy.util.text.StringUtil;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Optional;

/**
 * @author chenzy
 * @since 2020-04-28
 */
public class TableUtil {
    private TableUtil() {
    }

    private static TableUtil instance = new TableUtil();

    public static TableUtil instance() {
        return instance;
    }

    private MyMap<Class<?>, Field> pkMap = new MyMap<>();
    public void clear(){
        pkMap.clear();
    }
    public <Bean> StringMap getPKMap(Bean bean){
        if (bean == null) {
            return StringMap.empty();
        }
        var field=getPKField(bean).get();
        try {
            return field==null?StringMap.empty():new StringMap(1
                    ,field.isAnnotationPresent(JsonProperty.class)? field.getAnnotation(JsonProperty.class).value():field.getName(),field.get(bean));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return StringMap.empty();
        }

    }
    public <Bean> Boolean clearPKField(Bean bean){
        if (bean == null) {
            return false;
        }
        var fieldOptional=getPKField(bean);
        if (fieldOptional.isEmpty()){
            return false;
        }
        try {
            fieldOptional.get().set(bean,null);
            return true;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return false;
        }
    }
    private  <Bean> Optional<Field> getPKField(Bean bean){
        if (bean == null) {
            return Optional.empty();
        }
        var beanClass = bean.getClass();
        Field field = null;
        if (pkMap.containsKey(beanClass)) {
            field = pkMap.get(beanClass);
        } else {
            field = Arrays.stream(beanClass.getDeclaredFields()).filter(temp -> temp.isAnnotationPresent(PK.class)).findFirst().get();
            if (field == null) {
                return null;
            }
            field.setAccessible(true);
            pkMap.put(beanClass,field);
        }
        return Optional.of(field);
    }
    public <Bean> Optional<Object> getPK(Bean bean) {
        try {
            var field=getPKField(bean).get();
            return field==null?Optional.empty():Optional.of(field.get(bean));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return Optional.empty();
        }
    }

    public static <Bean> String getTableName(Class<Bean> beanClass) {
        String tableName = null;
        if (beanClass.isAnnotationPresent(Table.class)) {
            tableName = (beanClass.getAnnotation(Table.class)).value();
        }
        if (StringUtil.isBlank(tableName)) {
            tableName = StringUtil.lowFirst(beanClass.getSimpleName().replace(".class", ""));
        }
        return tableName;
    }
}
